﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace Xyzzer.AsyncUI
{
    partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        private async void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            await Task.Delay(1000);

            await new MessageDialog(
                "Welcome you to the world of UI development!",
                "Hello async/await!").ShowAsync();

            RunAsyncAwaitVersion();
            //RunEventDrivenVersion();
            //RunEventDrivenVersionUsingIteratorBlock();
        }

        //------------------------------------------------------------------------------------
        // Async/Await version (26 lines).
        // Control flow logic visible almost as clearly as if the code was running synchronously.
        private async void RunAsyncAwaitVersion()
        {
            while (true)
            {
                await Task.Delay(500);

                var result = await Dialog.Show(
                    "Hello async/await!",
                    "We welcome you to the world of UI development!",
                    "Cool!",
                    "Awesome!");

                await Task.Delay(500);

                result = await Dialog.Show(
                    "You said",
                    string.Format("\"{0}\"", result),
                    "Repeat",
                    "Exit");

                if (result == "Exit")
                {
                    Application.Current.Exit();
                }
            }        
        }

        //------------------------------------------------------------------------------------
        // Event driven state machine version (62 lines)
        // The classic implementation is roughly twice the length of the async/await version,
        // it uses an enum to drive the state machine, a timer, a field that stores
        // the last result and includes 4 methods with the control logic spread over all of them.
        private enum EventDrivenDialogState
        {
            FirstMessage,
            SecondMessage,
        }

        private EventDrivenDialogState nextMessage;
        private string lastResult;

        private void RunEventDrivenVersion()
        {
            EventDrivenDialog.DialogDismissed += new EventHandler<EventDrivenCustomDialog.TextEventArgs>(EventDrivenDialog_DialogDismissed);
            nextMessage = EventDrivenDialogState.FirstMessage;
            MoveNext();
        }

        private void MoveNext()
        {
            switch (nextMessage)
            {
                case EventDrivenDialogState.FirstMessage:
                    EventDrivenDialog.Show(
                        "Hello async/await!",
                        "We welcome you to the world of UI development!",
                        "Cool!",
                        "Awesome!");
                    nextMessage = EventDrivenDialogState.SecondMessage;
                    break;
                case EventDrivenDialogState.SecondMessage:
                    EventDrivenDialog.Show(
                        "You said",
                        string.Format("\"{0}\"", lastResult),
                        "Repeat",
                        "Exit");
                    nextMessage = EventDrivenDialogState.FirstMessage;
                    break;
            }
        }

        private void EventDrivenDialog_DialogDismissed(object sender, EventDrivenCustomDialog.TextEventArgs e)
        {
            lastResult = e.Text;

            if (nextMessage == EventDrivenDialogState.FirstMessage &&
                lastResult == "Exit")
            {
                Application.Current.Exit();
            }

            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(0.5);
            timer.Tick += timer_Tick;
            timer.Start();
        }

        private void timer_Tick(object sender, object e)
        {
            var timer = (DispatcherTimer)sender;
            timer.Tick -= timer_Tick;
            timer.Stop();
            MoveNext();
        }

        //------------------------------------------------------------------------------------
        // Event driven state machine version using an iterator block (63 lines)
        // The iterator block shows state machine logic almost as clearly
        // as using the async/await keywords, but the overall infrastructure is
        // still rather complicated and takes as much code as the classic one.
        private IEnumerator stateMachineEnumerator;
        private string lastResult2;

        private void RunEventDrivenVersionUsingIteratorBlock()
        {
            EventDrivenDialog.DialogDismissed += new EventHandler<EventDrivenCustomDialog.TextEventArgs>(EventDrivenDialog_DialogDismissed2);
            this.stateMachineEnumerator = StateMachineIteratorBlock().GetEnumerator();
            this.stateMachineEnumerator.MoveNext();
        }

        private void EventDrivenDialog_DialogDismissed2(object sender, EventDrivenCustomDialog.TextEventArgs e)
        {
            lastResult2 = e.Text;
            this.stateMachineEnumerator.MoveNext();
        }

        private IEnumerable<int> StateMachineIteratorBlock()
        {
            while (true)
            {
                StateMachineEnumeratorWait(500);
                yield return 1;

                EventDrivenDialog.Show(
                    "Hello async/await!",
                    "We welcome you to the world of UI development!",
                    "Cool!",
                    "Awesome!");
                yield return 1;

                StateMachineEnumeratorWait(500);
                yield return 1;

                EventDrivenDialog.Show(
                    "You said",
                    string.Format("\"{0}\"", lastResult2),
                    "Repeat",
                    "Exit");
                yield return 1;

                if (lastResult2 == "Exit")
                {
                    Application.Current.Exit();
                }
            }
        }

        private void StateMachineEnumeratorWait(int delay)
        {
            var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(delay) };
            EventHandler<object> eh = null;

            eh = (s, e) =>
            {
                timer.Tick -= eh;
                timer.Stop();
                this.stateMachineEnumerator.MoveNext();

            };

            timer.Tick += eh;
            timer.Start();
        }
    }
}
